package com.yh.csx.business.test.util;


import com.alibaba.fastjson.JSON;
import com.yh.csx.business.api.entity.CommonResponse;
import com.yh.csx.business.api.enums.BizError;
import io.swagger.annotations.ApiOperation;
import org.springframework.cloud.openfeign.SpringQueryMap;
import org.springframework.http.*;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.Map;
import java.util.regex.Pattern;

/**
 * @创建人 霍钧城
 * @创建时间 2019年11月06日 15:12:00
 * @描述
 */
public class JunitUtils {
    private static volatile RestTemplate restTemplate;
    private static MediaType contentType;
    private static String loginToken="";
    /**
     *@描述 获得RestTemplate
     *@参数  []
     *@返回值  org.springframework.web.client.RestTemplate
     *@创建人  霍钧城
     *@创建时间  2019/11/7
     *@修改历史：
     */
    public static RestTemplate getRestTemplate() {
        if (restTemplate == null) {
            // 此处控制了锁的粒度，效果就是后续获取实例不用争抢锁
            synchronized (RestTemplate.class) {
                if (restTemplate == null) {
                    restTemplate = new RestTemplate();
                }
            }
        }
        return restTemplate;
    }
    /**
     *@描述 获得请求头
     *@参数  []
     *@返回值  org.springframework.http.HttpHeaders
     *@创建人  霍钧城
     *@创建时间  2019/11/7
     *@修改历史：
     */
    public static HttpHeaders genHttpHeaders(){
        HttpHeaders requestHeaders = new HttpHeaders();
        requestHeaders.add("login-token",loginToken);
        requestHeaders.setContentType(contentType);
        return requestHeaders;
    }
    /**
     *@描述 设置Content-Type
     *@参数  [mediaTypeVal]
     *@返回值  void
     *@创建人  霍钧城
     *@创建时间  2019/11/7
     *@修改历史：
     */
    private static void setContentType(MediaType mediaType){
        contentType=mediaType;
    }
    /**
     *@描述 根据url和Method 获得TestEntity对象
     *@参数  [url, method]
     *@返回值  util.TestEntity
     *@创建人  霍钧城
     *@创建时间  2019/11/7
     *@修改历史：
     */
    public static TestEntity getTestEntity(String url, Method method){
        //根据入参注解，设置请求参数
        Annotation[][] annotations=method.getParameterAnnotations();
        setContentType(MediaType.APPLICATION_JSON);//默认
        if(annotations.length>0){
            MediaType checkMediaType=null;
            for (Annotation[] annotation : annotations) {
                if(checkMediaType!=MediaType.APPLICATION_JSON){
                    for (Annotation annotation1 : annotation) {
                        if(annotation1 instanceof RequestParam){
                            setContentType(MediaType.APPLICATION_FORM_URLENCODED);
                        }
                        if(annotation1 instanceof RequestBody){
                            setContentType(MediaType.APPLICATION_JSON);
                            checkMediaType=MediaType.APPLICATION_JSON;
                        }
                        if(annotation1 instanceof SpringQueryMap){
                            setContentType(MediaType.APPLICATION_FORM_URLENCODED);
                        }
                        if(annotation1 instanceof PathVariable){
                            setContentType(MediaType.APPLICATION_JSON);
                            checkMediaType=MediaType.APPLICATION_JSON;
                        }
                    }
                }
            }
        }
        TestEntity testEntity=new TestEntity();
        testEntity.setReturnType(method.getReturnType());
        testEntity.setContentType(contentType);
        ApiOperation methodName=method.getAnnotation(ApiOperation.class);
        if(methodName!=null){
            testEntity.setMethodName(methodName.value());
        }else{
            testEntity.setMethodName("未设置ApiOperation，无中文方法名");
        }
        if (method.isAnnotationPresent(GetMapping.class)) {
            testEntity.setHttpMethod(HttpMethod.GET);
            testEntity.setUrl(url+mappingStr(method.getAnnotation(GetMapping.class).value()));
        }
        if (method.isAnnotationPresent(PostMapping.class)) {
            testEntity.setHttpMethod(HttpMethod.POST);
            testEntity.setUrl(url+mappingStr(method.getAnnotation(PostMapping.class).value()));
        }
        if (method.isAnnotationPresent(PutMapping.class)) {
            testEntity.setHttpMethod(HttpMethod.PUT);
            testEntity.setUrl(url+mappingStr(method.getAnnotation(PutMapping.class).value()));
        }
        if (method.isAnnotationPresent(DeleteMapping.class)) {
            testEntity.setHttpMethod(HttpMethod.DELETE);
            testEntity.setUrl(url+mappingStr(method.getAnnotation(DeleteMapping.class).value()));
        }
        if (method.isAnnotationPresent(RequestMapping.class)) {
            RequestMapping requestMapping=method.getAnnotation(RequestMapping.class);
            if(RequestMethod.GET==requestMapping.method()[0]){
                testEntity.setHttpMethod(HttpMethod.GET);
            }
            if(RequestMethod.PUT==requestMapping.method()[0]){
                testEntity.setHttpMethod(HttpMethod.PUT);
            }
            if(RequestMethod.POST==requestMapping.method()[0]){
                testEntity.setHttpMethod(HttpMethod.POST);
            }
            if(RequestMethod.DELETE==requestMapping.method()[0]){
                testEntity.setHttpMethod(HttpMethod.DELETE);
            }
            testEntity.setUrl(url+"/"+mappingStr(requestMapping.value()));
        }
        return testEntity;
    }
    /**
     *@描述 获得方法Mapping 内的值
     *@参数  [arr]
     *@返回值  java.lang.String
     *@创建人  霍钧城
     *@创建时间  2019/11/7
     *@修改历史：
     */
    public static String mappingStr(String[] arr){
        if(arr==null || arr.length==0){
            return "";
        }else{
            return arr[0];
        }
    }
    /**
     *@描述 检查请求，返回组织好的TestEntity对象
     *@参数  []
     *@返回值  util.TestEntity
     *@创建人  霍钧城
     *@创建时间  2019/11/7
     *@修改历史：
     */
    public static TestEntity checkRequest(final String ipAndPort,final String token) throws Exception{
        loginToken=token;
        //上一级的方法堆栈
        String currMethodName =Thread.currentThread().getStackTrace()[2].getMethodName().replace("test", "").toLowerCase();
        String currClassName=Thread.currentThread().getStackTrace()[2].getClassName();
        TestEntity testEntity=null;
        //替换Junit4 自动生成(包、类)增加的Test字符
        currClassName=currClassName.replaceFirst("Test","");
        Class<?> clazz = Class.forName(currClassName);//UserLoginController.class;
        Method[] methods = clazz.getDeclaredMethods();
        for (Method method : methods) {
            if (currMethodName.equals(method.getName().toLowerCase())) {
                testEntity= getTestEntity("http://"+ipAndPort+clazz.getAnnotation(RequestMapping.class).value()[0],method);
            }
        }
        return testEntity;
    }
    /**
     *@描述 校验响应
     *@参数  [response]
     *@返回值  void
     *@创建人  霍钧城
     *@创建时间  2019/11/7
     *@修改历史：
     */
    public static void checkResponse(CommonResponse response,Integer... responseSuccessCodes) throws Exception {
        System.out.println("==============================================");
        System.out.println("响应状态码："+response.getCode());
        System.out.println("响应消息："+response.getMessage());
        System.out.println(toFormat(JSON.toJSONString(response.getData()),true,true));
        System.out.println("==============================================");
        if(responseSuccessCodes!=null && responseSuccessCodes.length>0){
            boolean throwBoolean =true;
            for (Integer responseSuccessCode : responseSuccessCodes) {
                if(responseSuccessCode.intValue()==response.getCode() || BizError.SUCCESS.getCode()==response.getCode()){
                    throwBoolean=false;
                    break;
                }
            }
            if(throwBoolean){
                throw new Exception("状态码失败");
            }
        }else{
            if(BizError.SUCCESS.getCode()!=response.getCode()){
                throw new Exception("状态码失败");
            }
        }
    }
    /**
     *@描述 请求拼装url+json
     *@参数  [urlMap, testEntity]
     *@返回值  org.springframework.http.ResponseEntity<com.yh.csx.business.api.entity.CommonResponse>
     *@创建人  霍钧城
     *@创建时间  2019/12/9
     *@修改历史：
     */
    public static <T> ResponseEntity<T> getResponseEntity(Map urlMap, TestEntity testEntity){
        requestMapToUrl(testEntity,(Map<String,String>)urlMap);
        return getResponseEntity(testEntity);
    }

    /**
     *@描述 根据不同的请求和入参进行具体请求
     *@参数  [testEntity]
     *@返回值  org.springframework.http.ResponseEntity<com.yh.csx.business.api.entity.CommonResponse>
     *@创建人  霍钧城
     *@创建时间  2019/11/7
     *@修改历史：
     */
    public static <T> ResponseEntity<T> getResponseEntity(TestEntity testEntity){
        String jsonStr=JSON.toJSONString(testEntity.getRequestObj());
        System.out.println("==============================================");
        System.out.println("请求方法名称："+testEntity.getMethodName());
        System.out.println("请求方式："+testEntity.getHttpMethod().name());
        System.out.println("请求contentType："+testEntity.getContentType());
        System.out.println("请求参数："+toFormat(jsonStr,true,true));
        System.out.println("响应类型："+testEntity.getReturnType());
        ResponseEntity<T> responseResponseEntity=null;
        if(testEntity.getHttpMethod()== HttpMethod.POST || testEntity.getHttpMethod()== HttpMethod.PUT){
            HttpEntity<T> request =null;
            //设置入参和Header
            if(testEntity.getRequestObj() instanceof Map){
                requestMapToUrl(testEntity,(Map<String,String>)JSON.parse(jsonStr));
                responseResponseEntity = JunitUtils.getRestTemplate().exchange(testEntity.getUrl(),
                        testEntity.getHttpMethod(),
                        new HttpEntity<String>(JunitUtils.genHttpHeaders()),
                        testEntity.getReturnType()
                );
            }else{
                System.out.println("请求方法URL："+testEntity.getUrl());
                if(testEntity.getHttpMethod()== HttpMethod.POST){
                    request = new HttpEntity(testEntity.getRequestObj(), JunitUtils.genHttpHeaders());
                    responseResponseEntity = JunitUtils.getRestTemplate().postForEntity(testEntity.getUrl(), request,testEntity.getReturnType());
                }else{
                    responseResponseEntity=exchange(testEntity.getUrl(),testEntity.getHttpMethod(),testEntity.getReturnType(),jsonStr);
                }
            }
        }
        if(testEntity.getHttpMethod()== HttpMethod.GET || testEntity.getHttpMethod()== HttpMethod.DELETE){
            if(testEntity.getRequestObj() instanceof Map){
                requestMapToUrl(testEntity,(Map<String,String>)testEntity.getRequestObj());
            }else{
                requestMapToUrl(testEntity,(Map<String,String>)JSON.parse(jsonStr));
            }
            //把url中{}替换成对应的值
            responseResponseEntity = JunitUtils.getRestTemplate().exchange(testEntity.getUrl(),
                    testEntity.getHttpMethod(),
                    new HttpEntity<String>(JunitUtils.genHttpHeaders()),
                    testEntity.getReturnType()
            );
        }
        System.out.println("==============================================");
        return responseResponseEntity;
    }
    /**
     *@描述 根据requestObj 转MAP 转URL
     *@参数  [testEntity, map]
     *@返回值  void
     *@创建人  霍钧城
     *@创建时间  2019/11/8
     *@修改历史：
     */
    private static void requestMapToUrl(TestEntity testEntity,Map<String,String> map){
        String url=testEntity.getUrl();
        if(url.indexOf("{")>=0){
            //拼装参数url： id/123456
            if(testEntity.getRequestObj()!=null){
                for (Map.Entry<String, String> entry : map.entrySet()) {
                    url=url.replace(entry.getKey(),String.valueOf(entry.getValue()));
                }
                testEntity.setUrl(url);
            }
        }else{
            if(testEntity.getRequestObj()!=null){
                url=url+"?";
                for (Map.Entry<String, String> entry : map.entrySet()) {
                    url=url+(Pattern.compile("[{}]").matcher(entry.getKey()).replaceAll("").trim()+"="+String.valueOf(entry.getValue()))+"&";
                }
                testEntity.setUrl(url);
            }

        }
        System.out.println("请求方法URL："+testEntity.getUrl());
    }
    /**
     *@描述 根据长度获得随机数，最长为时间戳长度
     *@参数  [length]
     *@返回值  java.lang.String
     *@创建人  霍钧城
     *@创建时间  2019/11/7
     *@修改历史：
     */
    public static String getRandomString(){
        return String.valueOf(System.currentTimeMillis());
    }

    /**
     *@描述 发送/获取 服务端数据(主要用于解决发送put,delete方法无返回值问题).
     *@参数  [url, method, bodyType, paramJsonString]
     *@返回值  T
     *@创建人  霍钧城
     *@创建时间  2019/11/11 
     *@修改历史：
     */
    public static ResponseEntity exchange(String url, HttpMethod method, Class bodyType,String paramJsonString) {
        HttpEntity<String> entity = new HttpEntity<>(paramJsonString, JunitUtils.genHttpHeaders());
        RestTemplate restTemplate = new RestTemplate();
        ResponseEntity resultEntity = restTemplate.exchange(url, method, entity, bodyType);
        return resultEntity;
    }
    /**
     * 对json字符串进行格式化
     * @param content 要格式化的json字符串
     * @param indent 是否进行缩进(false时压缩为一行)
     * @param colonWithSpace key冒号后是否加入空格
     * @return
     */
    public static String toFormat(String content, boolean indent, boolean colonWithSpace) {
        if (content == null) return null;
        StringBuilder sb = new StringBuilder();
        int count = 0;
        boolean inString = false;
        String tab = "\t";
        for (int i = 0; i < content.length(); i ++) {
            char ch = content.charAt(i);
            switch (ch) {
                case '{':
                case '[':
                    sb.append(ch);
                    if (!inString) {
                        if (indent) {
                            sb.append("\n");
                            count ++;
                            for (int j = 0; j < count; j ++) {
                                sb.append(tab);
                            }
                        }

                    }
                    break;
                case '\uFEFF': //非法字符
                    if (inString) sb.append(ch);
                    break;
                case '}':
                case ']':
                    if (!inString) {
                        if (indent) {
                            count --;
                            sb.append("\n");
                            for (int j = 0; j < count; j ++) {
                                sb.append(tab);
                            }
                        }

                        sb.append(ch);
                    } else {
                        sb.append(ch);
                    }
                    break;
                case ',':
                    sb.append(ch);
                    if (!inString) {
                        if (indent) {
                            sb.append("\n");
                            for (int j = 0; j < count; j ++) {
                                sb.append(tab);
                            }
                        } else {
                            if (colonWithSpace) {
                                sb.append(' ');
                            }
                        }
                    }
                    break;
                case ':':
                    sb.append(ch);

                    if (!inString) {
                        if (colonWithSpace) {  //key名称冒号后加空格
                            sb.append(' ');
                        }
                    }
                    break;
                case ' ':
                case '\n':
                case '\t':
                    if (inString) {
                        sb.append(ch);
                    }
                    break;
                case '"':
                    if (i > 0 && content.charAt(i - 1) != '\\') {
                        inString = !inString;
                    }
                    sb.append(ch);
                    break;
                default:
                    sb.append(ch);
                    break;
            }
        }
        return sb.toString();
    }
    /**
     *@描述 json To Object
     *@参数  [json, type]
     *@返回值  T
     *@创建人  霍钧城
     *@创建时间  2019/11/15
     *@修改历史：
     */
    public static <T> T  jsonToObject(final String json, final Class<T> type){
        return JSON.parseObject(json,type);
    }
}
